package projetDames.composant;

import java.awt.Graphics;
import java.io.Serializable;
import java.util.ArrayList;

import javax.swing.JPanel;

// voir trouverVoisin() entre Dame et Pion
// voir abstract meilleurChemin
/**
 * Cette classe decrit une piece du jeu de dame. Elle herite des classe Pion et
 * Dame.
 */
public abstract class Piece implements Commun, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/** couleur d'une piece. */
	protected boolean couleur;
	/** Coordonnees de la piece */
	protected Pointp xy;
	/** Plateau de jeu sur lequel est positionne l'ensemble des pieces jouables */
	protected Piece[][] plateau;

	// variable de classe utiles pour la methode meilleurChemin();
	/**
	 * Apres execution de la methode meilleurChemin, liste contenant le meilleur
	 * chemin pour la piece courante
	 */
	protected ArrayList<ArrayList<Pointp>> meilleurChemin = new ArrayList<ArrayList<Pointp>>();
	/** Taille du parcours du meilleur chemin */
	protected int tailleMeilleurChemin = 1;
	/**
	 * Apres execution de la methode meilleurChemin, liste contentant les pieces
	 * mangees
	 */
	protected ArrayList<Pointp> pionsManges = new ArrayList<Pointp>();
	/** Taille de la liste contentant les pieces mangees */
	private int taillePionsManges = 0;
	/**
	 * Liste du chemin courant d'une prise par la piece courante. Variable
	 * necessaire à la methode meilleurChemin
	 */
	protected ArrayList<Pointp> cheminCourant = new ArrayList<Pointp>();

	/**
	 * @param coul
	 *            couleur de la piece
	 * @param x
	 *            coordonnee x de la piece
	 * @param y
	 *            coordonnee y de la piece
	 * @param plat
	 *            plateau de jeu
	 */
	public Piece(boolean coul, int x, int y, Piece[][] plat) {
		this.couleur = coul;
		this.xy = new Pointp(x, y);
		this.plateau = plat;
	}

	/**
	 * @return la variable de classe pionsManges contenant la liste des pieces
	 *         mangees
	 */
	public ArrayList<Pointp> getPionsManges() {
		return this.pionsManges;
	}

	/**
	 * @return la variable de classe contenant la coordonnee X de la piece
	 */
	public int getPositionX() {
		return this.xy.x;
	}

	/**
	 * @return la variable de classe contenant la coordonnee Y de la piece
	 */
	public int getPositionY() {
		return this.xy.y;
	}

	/**
	 * @return la couleur de la piece
	 */
	public boolean getCouleur() {
		return this.couleur;
	}

	/**
	 * @return liste contenant le meilleur chemin pour la piece courante
	 */
	public ArrayList<ArrayList<Pointp>> getMeilleurChemin() {
		return this.meilleurChemin;
	}

	public int getTaillePionsManges() {
		int i = 0;
		for (int k = 0; k < this.pionsManges.size(); k++) {
			i++;
		}

		return i;
	}

	public int getTailleMeilleurChemin(int n) {
		int i = 0;
		for (int k = 0; k < this.meilleurChemin.get(n).size(); k++) {
			i++;
		}

		return i;
	}

	/**
	 * Affecte le nouveau plateau passe en parametre a la variable de classe
	 * plateau
	 * 
	 * @param plat
	 *            plateau de jeu
	 */
	public void setPlateau(Piece[][] plat) {
		this.plateau = plat;
	}

	/**
	 * Affecte les pieces mangees a la variable de classe pionsManges a partir
	 * de la liste envoye en parametre
	 * 
	 * @param list
	 */
	public void addPionsManges(ArrayList<Pointp> list) {
		this.pionsManges.clear();
		for (Pointp pts : list)
			this.pionsManges.add(new Pointp(pts.x, pts.y));

	}

	/**
	 * Vide la variable de classe meilleurChemin
	 */
	public void clearList() {
		this.meilleurChemin.clear();
	}

	public void addList(ArrayList<Pointp> p) { // ajoute a meilleurChemin la
												// liste envoyé
		ArrayList<Pointp> tmp = new ArrayList<Pointp>();
		for (Pointp pts : p)
			tmp.add(new Pointp(pts.x, pts.y));
		this.meilleurChemin.add(tmp);
	}

	/**
	 * Affecte a la variable de classe tailleMeilleurChemin une nouvelle taille
	 * envoye en parametre
	 * 
	 * @param nb
	 */
	public void setTailleMeilleurChemin(int nb) {
		this.tailleMeilleurChemin = nb;
	}

	// public int getTailleMeilleurChemin() { return this.tailleMeilleurChemin;
	// }

	/**
	 * Methode abstraite retournant les coordonnees des voisins direct
	 * 
	 * @param p
	 * @return un tableau[4] des coordonnees des voisins d'un pion
	 */
	public abstract Pointp[] trouverVoisin(Pointp p);

	/**
	 * Methode recursive qui permet de trouver le meilleur chemin pour une
	 * piece. Elle ecrit dans la variable de classe meilleurChemin la liste du
	 * meilleur chemin pour une piece, et dans pionsManges, les pieces qui sont
	 * mangees en parcourant le meilleur chemin.
	 * 
	 * @param p
	 * @param rang
	 */
	public abstract void meilleurChemin(Pointp p, int rang);

	/**
	 * Si la case au coordonnees x et y contient une piece, la methode retourne
	 * son etat par rapport au parametre. Si la case est vide, retourne vide
	 * 
	 * @param pionVoisin
	 *            objet Pointp contenant les coordonnees d'une piece
	 * @return un entier correspondant a l'etat (ami, ennemi) d'une piece du
	 *         plateau par rapport au parametre envoye.
	 * @return Retourne l'etat vide si il n'y a pas de piece sur la case
	 *         courante du plateau
	 */
	public int etat(Pointp pionVoisin) {
		int rep = _VIDE;
		if (xy.dansBornes() && pionVoisin.dansBornes()) {
			boolean couleur = this.plateau[xy.x][xy.y].getCouleur();

			if (this.plateau[pionVoisin.x][pionVoisin.y] != null) {
				if (this.plateau[pionVoisin.x][pionVoisin.y].getCouleur() != couleur) {
					rep = _ENNEMI;
				} else {
					rep = _AMI;
				}
			} else {
				rep = _VIDE;
			}
		} else {
			rep = _VIDE;
		}
		return rep;
	}

	/**
	 * Test si une case est vide ou non
	 * 
	 * @param p
	 *            coordonnees d'une case sur le plateau
	 * @return un boolean, vrai si la case au coordonnees p est vide, faux sinon
	 */
	public boolean estVide(Pointp p) {
		return this.plateau[p.x][p.y] == null;
	}

	/**
	 * Permet de savoir si une case est presente dans une liste de cases
	 * 
	 * @param p
	 *            coordonnees d'une case sur le plateau
	 * @param list
	 *            liste des coordonnees de cases
	 * @return vrai si la paremetre p est present dans la liste list envoye en
	 *         parametre
	 */
	public boolean listPointContient(Pointp p, ArrayList<Pointp> list) {
		int i = 0;
		int max = list.size();
		while (i < max && !p.egal(list.get(i))) { // (i<max && (p.x !=
													// list.get(i).x || p.y !=
													// list.get(i).y)) {
			i++;
		}
		return i != max;
	}

	/**
	 * Permet de savoir si a partir d'un tableau de voisins et d'une liste
	 * d'ennemis, il existe des ennemis mangeables
	 * 
	 * @param tab
	 *            tableau contenant des coordonnees de cases
	 * @param list
	 *            liste contenant des coordonnees de cases
	 * @return vrai si a partir d'une liste d'ennemi il existe une piece ennemie
	 *         mangeable dans le tableau de voisins envoyé, faux sinon
	 */
	// TODO existeEnnemi et existeEnnemiDames seront fusionné
	public boolean existeEnnemi(Pointp[] tab, ArrayList<Pointp> list) {
		boolean rep = false;
		int i = 0;
		while (i < tab.length && !rep) {
			if (listPointContient(tab[i], list)) {
				rep = false;
			} else {
				if (etat(tab[i]) == _ENNEMI) {
					rep = true;
				}
			}
			i++;
		}
		return rep;
	}

	/**
	 * Permet de savoir si il y a au moins un ennemi dans un tableau[4] envoye
	 * en parametre
	 * 
	 * @param tab
	 *            tableau contenant des coordonnees de cases
	 * @return vrai si il y a au moins un ennemi dans le tableau[4] tab envoye
	 *         en parametre, faux sinon
	 */
	public boolean existeEnnemi(boolean[] tab) {
		boolean rep = false;
		int i = 0;
		while (i < 4 && !rep) {
			if (tab[i] == true) {
				rep = true;
			}
			i++;
		}
		return rep;
	}

	/**
	 * Affiche la variable de classe meilleurChemin
	 */
	public void afficheMeilleurChemin() {
		System.out.println("\nSolutions Meilleur Chemin :");
		System.out.println("taille: " + this.meilleurChemin.size());

		System.out.println(meilleurChemin);
	}

	/**
	 * Methode abstraite qui permet de dessiner un pion ou une dame aux
	 * coordonnees p
	 * 
	 * @param p
	 *            coordonnees d'une case du plateau
	 * @param g
	 *            objet permettant de dessiner
	 */
	public abstract void dessine(Graphics g, JPanel p, int x, int y);

	// TODO test a surpprimer
	public void afficheVoisin(Pointp[] tab, int x, int y) {
		System.out.print("voisin de :" + x + "," + y + "\n");
		System.out.print("voisin 0 " + tab[0].x + tab[0].y);
		if (this.plateau[tab[0].x][tab[0].y] != null && tab[0].dansBornes()) {
			System.out.println("Couleur: "
					+ this.plateau[tab[0].x][tab[0].y].getCouleur());
		}
		System.out.print("voisin 1 " + tab[1].x + tab[1].y);
		if (this.plateau[tab[1].x][tab[1].y] != null && tab[1].dansBornes()) {
			System.out.println(" Couleur: "
					+ this.plateau[tab[1].x][tab[1].y].getCouleur());
		}
		System.out.print("voisin 2 " + tab[2].x + tab[2].y);
		if (this.plateau[tab[2].x][tab[2].y] != null && tab[2].dansBornes()) {
			System.out.println("Couleur: "
					+ this.plateau[tab[2].x][tab[2].y].getCouleur());
		}
		System.out.print("voisin 3 " + tab[3].x + tab[3].y);
		if (this.plateau[tab[3].x][tab[3].y] != null && tab[3].dansBornes()) {
			System.out.println("Couleur: "
					+ this.plateau[tab[3].x][tab[3].y].getCouleur());
		}
	}

	/**
	 * Redefinition de la methode toString
	 */
	public String toString() {
		String result;
		if (couleur == _NOIR) {
			result = "N";
		} else {
			result = "B";
		}
		return result;

	}

}
